<template>
    <div ref="boxRef">
        <slot :code="code" :problem="problem" :response="response" :loading="loading" :reload="reload"></slot>
    </div>
</template>


<script setup lang="ts">
/* eslint-disable */
import {ref, watch} from "vue";

/**
 * 后台请求骨架
 *
 * 简单地说，就是组件版的 ajax 请求，
 *
 * 做数据展示界面的时候，这个组件会非常好用：
 *
 *  1、可以根据当前 API，提前设计好 404、500 等服务降级界面；
 *  2、可以很好地对接骨架屏的设计，有些时候可以省去 js 部分的所有代码。
 */
interface Props {
    // 页面载入后立即查询？
    autoLoad?: boolean;
    /** 查询条件，带联动效果 */
    where?: Record<string, any>;
    // 数据查询执行器函数
    provider?: (params: Record<string, any>) => Promise<unknown>;
}

const props = withDefaults(defineProps<Props>(), {autoLoad: true});

const boxRef = ref();

// 请求异常，服务降级界面配置
const fallback_style = 'error-ajax';

// 是否正在载入数据，如果需要制作骨架屏，或者局部加载条，这个属性很好用
const loading = ref(false);

// http-status
const code = ref(0);
// error content
const problem = ref('');
// normal response
const response = ref(undefined);

/**
 * 重新载入数据
 */
const reload = () => {
    if (loading.value) {
        return;
    }

    loading.value = true;
    props.provider(props.where).then((ret) => {
        code.value = 0;
        problem.value = {};
        response.value = ret;

        //
        boxRef.value.classList.remove(fallback_style);
    }).catch(err => {
        console.error(err);

        code.value = 500;
        problem.value = err;
        response.value = undefined;

        // fallback page
        boxRef.value.classList.add(fallback_style);
    }).finally(() => {
        loading.value = false;
    })
}

watch(() => props.where, () => {
    reload();
});

// 组件初始化
{
    if (props.autoLoad) {
        reload();
    }
}
</script>
